#!/usr/bin/env python

import sys
import xml.sax
import optparse
import shutil
import urllib
import os 

class Handler( xml.sax.ContentHandler):

    def __init__(self,options,destDir):
        self.options = options
        self.destDir=destDir
    
    def norm(self,s):
        ret = ""
        for c in s:
            if ( c.isalpha() or c.isdigit() ) :
                ret += c
        return ret

    def copyTrack(self,trackID):
        track = self.tracks[trackID]
        #print self.playlistName, track['artist'], track['name']

        src = track['location']
        artist = self.norm(track['artist'])
        name = self.norm(track['name'])
        extention = src[ -3: ]
        kind = track['kind']

        prefix = "file://localhost"
        if not src.startswith(prefix):
            print "Weird location of %s"%src
          
        src = urllib.unquote( src )

        src = src[ len(prefix): ]

        if self.options.noDRM:
            if kind.find("Protected") > -1 :
                return

        self.copyCount += 1
        dest = "%s/%04d_%s-%s.%s"%(self.destDir,self.copyCount,artist,name,extention)
        if self.options.dryRun:
            print "cp %s %s"%(src,dest)
        if not self.options.dryRun:
           try:
               shutil.copy(src,dest)
           except:
               print "Failed to copy %s to %s"%(src,dest)
               return
           if self.options.verbose:
               print "Copied %s to %s"%(src,dest)

    def startDocument(self):
        self.value = ""
        self.doingTracks = False
        self.doingPlayLists = False
        self.keyValue = ""
        self.dictKey = ""
        self.trackCount=0
        self.tracks = {}
        self.copyTracks = False
        self.copyCount = 0;

    def startElement(self,tag,attributes):
        #print "start %s"%tag
        self.value = ""
        if ( tag == "dict" ):
            self.dictKey = self.keyValue

    def characters(self,data):
        #print "   read %s "%data 
        self.value += data 

    def endElement(self,tag):
        #print "tag %s value=%s"%(tag,self.value)
        if ( tag == 'key' and self.value == 'Tracks' ):
            self.doingTracks = True
            if self.options.verbose: print "Starting Tracks Parse"
        if ( tag == 'key' and self.value == 'Playlists' ):
            if self.options.verbose: print "Parsed %d tracks"%self.trackCount
            self.doingTracks = False
            self.doingPlayLists = True
            if self.options.verbose: print "Starting Playlists Parse"
        if ( tag == 'key'):
            self.keyValue = self.value
        if ( tag == "string" and self.keyValue == "Name"):
           self.trackName = self.value
        if ( tag == "string" and self.keyValue == "Artist"):
           self.trackArtist = self.value
        if ( tag == "string" and self.keyValue == "Album"):
           self.trackAlbum = self.value
        if ( tag == "string" and self.keyValue == "Location"):
           self.trackLocation = self.value
        if ( tag == "string" and self.keyValue == "Kind"):
           self.trackKind = self.value

        if ( tag == "string" and self.keyValue == "Name" and self.doingPlayLists):
           self.playlistName = self.value
           if self.options.verbose or self.options.list: 
               print "Playlist %s"%self.playlistName
           if ( self.playlistName == self.options.playlist ):
               if not self.options.list:
                   self.copyTracks = True
           else:
               self.copyTracks = False
        if ( tag == "integer" and self.keyValue == "Track ID"):
           trackID = int(self.value)
           #print "song id %d"%trackID
           if self.copyTracks:
               self.copyTrack( trackID )

        if ( tag == 'dict' and self.doingTracks ):
            self.trackCount += 1
            if ( self.trackCount % 100 == 0 ):
                if self.options.verbose: print "Parsed %d tracks"%self.trackCount
            #print "Track record"
            #print "   key: %s"%self.dictKey
            #print "   Artist: %s"%self.trackArtist
            #print "   Name: %s"%self.trackName
            #print "   Album: %s"%self.trackAlbum
            #print "   Location: %s"%self.trackLocation
            #print "   Kind: %s"%self.trackKind
            self.tracks[int(self.dictKey)] = { 'artist':self.trackArtist,
                                               'name':self.trackName,
                                               'album':self.trackAlbum,
                                               'location':self.trackLocation,
                                               'kind':self.trackKind }



def main():

    optionParser = optparse.OptionParser(version="%prog 0.1",
                                         description="Copies files from playlists in iTunes into the destination directory",
                                         usage="%prog [options] destinationDirectory")
    optionParser.add_option('--verbose','-v',action='store_true')
    optionParser.add_option('--noDRM','-n',
                            action='store_true',
                            help="Don't copy DRM protected files")
    optionParser.add_option('--list','-l',
                            action='store_true',
                            help="List play lists")
    optionParser.add_option('--dryRun','-d',
                            action='store_true',
                            help="Don't copy file, just show what would be done")
    optionParser.add_option('--playlist','-p',
                            action='store',
                            type="string",
                            help="ITunes playlist to copy")
    
    options, arguments = optionParser.parse_args()

    if options.list:
        arguments = [ "/-invalid-" ]

    if ( len(arguments) < 1 ):
        optionParser.error("Must provide a destination directory")
    if ( len(arguments) > 1 ):
        optionParser.error("Must provide only one destination directory")

    base = os.path.expanduser("~")
    fileName = base + "/Music/iTunes/iTunes Music Library.xml"

    file = open(fileName,'r')
    if not ( file ):
        print "could not open iTunes Library %s"%fileName
        return -1

    parser = xml.sax.make_parser()
    handler = Handler(options,arguments[0])
    parser.setContentHandler( handler )
    BUFSIZE = 8192

    while True:
        data = file.read(BUFSIZE)
        if not data:
            break
        parser.feed(data)
    
    return 0
    

if __name__ == "__main__":
    sys.exit(main())

